/**
 * User: alesj
 * Date: 2005.1.20
 * Time: 14:47:34
 * 
 * (C) Genera Lynx d.o.o.
 */

package com.generalynx.ecos.beans.orm;

import java.io.Serializable;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.*;
import org.hibernate.type.Type;

public abstract class ChainedInterceptorSupport implements Interceptor {

    protected final Log log = LogFactory.getLog(getClass());

    private Interceptor nextInterceptor;

    /**
     * As Hibernate doesn't support chaining of interceptors natively, we add the ability for
     * chaining via a delegate.
     *
     * @param nextInterceptor
     */
    public void setNextInterceptor(Interceptor nextInterceptor) {
        this.nextInterceptor = nextInterceptor;
    }

    public Interceptor getNextInterceptor() {
        return nextInterceptor;
    }

    /**
     * @see org.hibernate.Interceptor#instantiate(java.lang.String entityName, EntityMode entityMode, java.io.Serializable)
     */
    public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException {
        return (nextInterceptor != null) ? nextInterceptor.instantiate(entityName, entityMode, id) : null;
    }

    /**
     * @see org.hibernate.Interceptor#onLoad(java.lang.Object, java.io.Serializable,
            *      java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
     */
    public boolean onLoad(Object entity,
                          Serializable id,
                          Object[] state,
                          String[] propertyNames,
                          Type[] types)
            throws CallbackException {
        if (nextInterceptor != null) {
            return nextInterceptor.onLoad(entity, id, state, propertyNames, types);
        } else {
            return false;
        }
    }

    /**
     * @see org.hibernate.Interceptor#onFlushDirty(java.lang.Object, java.io.Serializable,
            *      java.lang.Object[], java.lang.Object[], java.lang.String[],
            *      org.hibernate.type.Type[])
     */
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
                                String[] propertyNames, Type[] types) throws CallbackException {
        if (nextInterceptor != null) {
            return nextInterceptor.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
        } else {
            return false;
        }
    }

    /**
     * @see org.hibernate.Interceptor#onSave(java.lang.Object, java.io.Serializable,
            *      java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
     */
    public boolean onSave(Object entity,
                          Serializable id,
                          Object[] state,
                          String[] propertyNames,
                          Type[] types)
            throws CallbackException {
        if (nextInterceptor != null) {
            return nextInterceptor.onSave(entity, id, state, propertyNames, types);
        } else {
            return false;
        }
    }

    /**
     * @see org.hibernate.Interceptor#onDelete(java.lang.Object, java.io.Serializable,
            *      java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
     */
    public void onDelete(Object entity,
                         Serializable id,
                         Object[] state,
                         String[] propertyNames,
                         Type[] types)
            throws CallbackException {
        if (nextInterceptor != null) {
            nextInterceptor.onDelete(entity, id, state, propertyNames, types);
        }
    }

    /**
     * @see org.hibernate.Interceptor#preFlush(java.util.Iterator)
     */
    public void preFlush(Iterator entities) throws CallbackException {
        if (nextInterceptor != null) {
            nextInterceptor.preFlush(entities);
        }
    }

    /**
     * @see org.hibernate.Interceptor#postFlush(java.util.Iterator)
     */
    public void postFlush(Iterator entities) throws CallbackException {
        if (nextInterceptor != null) {
            nextInterceptor.postFlush(entities);
        }
    }

    /**
     * @see org.hibernate.Interceptor#isTransient(Object)
     */
    public Boolean isTransient(Object entity) {
        if (nextInterceptor != null) {
            return nextInterceptor.isTransient(entity);
        } else {
            return null;
        }
    }

    public String getEntityName(Object object) throws CallbackException {
        if (nextInterceptor != null) {
            return nextInterceptor.getEntityName(object);
        } else {
            return null;
        }
    }

    public Object getEntity(String entityName, Serializable id) throws CallbackException {
        if (nextInterceptor != null) {
            return nextInterceptor.getEntity(entityName, id);
        } else {
            return null;
        }
    }

    public void afterTransactionBegin(Transaction tx) {
        if (nextInterceptor != null) {
            nextInterceptor.afterTransactionBegin(tx);
        }
    }

    public void beforeTransactionCompletion(Transaction tx) {
        if (nextInterceptor != null) {
            nextInterceptor.beforeTransactionCompletion(tx);
        }
    }

    public void afterTransactionCompletion(Transaction tx) {
        if (nextInterceptor != null) {
            nextInterceptor.afterTransactionCompletion(tx);
        }
    }

    /**
     * @see org.hibernate.Interceptor#findDirty(java.lang.Object, java.io.Serializable,
            *      java.lang.Object[], java.lang.Object[], java.lang.String[],
            *      org.hibernate.type.Type[])
     */
    public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames,
                           Type[] types) {
        if (nextInterceptor != null) {
            return nextInterceptor.findDirty(entity, id, currentState, previousState, propertyNames, types);
        } else {
            return null;
        }
    }

    public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
/*
        if (nextInterceptor != null) {
            nextInterceptor.onCollectionRecreate(collection, key);
        }
*/
    }

    public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
/*
        if (nextInterceptor != null) {
            nextInterceptor.onCollectionRemove(collection, key);
        }
*/
    }

    public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
/*
        if (nextInterceptor != null) {
            nextInterceptor.onCollectionUpdate(collection, key);
        }
*/
    }

    public String onPrepareStatement(String sql) {
/*
        if (nextInterceptor != null) {
            return nextInterceptor.onPrepareStatement(sql);
        }
*/
        return sql;
    }

    /**
     * Convenience methods subclasses can use to apply the id to a new entity if they override
     * the instantiate method.
     *
     * @param entityName
     * @param id
     * @param newEntity
     * @throws CallbackException
     */
    protected void setIdOnNewEntity(SessionFactory sessionFactory,
                                    String entityName,
                                    Serializable id,
                                    Object newEntity,
                                    EntityMode entityMode) throws HibernateException {
        sessionFactory.getClassMetadata(entityName).setIdentifier(newEntity, id, entityMode);
    }

}